//
// Created by benxb on 2021/11/16.
//

#include <common/config.h>

#include <utility>
#include "storage/disk/data_chunk_delete_bitmap.h"
#include "common/exception.h"
#include "common/util/file_util.h"

namespace benxdb {


DataChunkDeleteBitmap::DataChunkDeleteBitmap(const std::string& table_name) : table_name_(table_name) {
    bitmap_file_ = GlobalConfig::DeleteMapFile(table_name);
    db_io_.open(bitmap_file_, std::ios::binary | std::ios::in | std::ios::out);
    // directory or file does not exist
    if (!db_io_.is_open()) {
        db_io_.clear();
        // create a new file
        db_io_.open(bitmap_file_, std::ios::binary | std::ios::trunc | std::ios::out);
        db_io_.close();
        // reopen with original mode
        db_io_.open(bitmap_file_, std::ios::binary | std::ios::in | std::ios::out);
        if (!db_io_.is_open()) {
            throw Exception("can't open desc file");
        }
    }
}

DataChunkDeleteBitmap::~DataChunkDeleteBitmap() {
    db_io_.close();
}

bool DataChunkDeleteBitmap::DeleteRecord(uint64_t record_id) {
    uint64_t byte_no = record_id/64;
    uint64_t bit_no = record_id%64;
    uint64_t mask = 1 << bit_no;
    int64_t file_size = FileUtil::GetFileSize(bitmap_file_);
    uint64_t offset = byte_no*8;
    if (file_size <= (record_id+7)/8) {
        return false;
    }
    db_io_.seekp(offset);
    uint64_t origin;
    db_io_.read(reinterpret_cast<char *>(&origin), sizeof(origin));
    uint64_t raw = origin | mask;
    db_io_.seekp(offset);
    db_io_.write(reinterpret_cast<const char *>(&raw), sizeof(raw));
    db_io_.flush();
    return true;
}

bool DataChunkDeleteBitmap::IsDelete(uint64_t record_id) {
    uint64_t byte_no = record_id/64;
    uint64_t bit_no = record_id%64;
    uint64_t mask = 1 << bit_no;
    uint64_t offset = byte_no*8;
    db_io_.seekp(offset);
    uint64_t origin;
    db_io_.read(reinterpret_cast<char *>(&origin), sizeof(origin));
    return origin & mask;
}

bool DataChunkDeleteBitmap::DeleteBatch(const std::vector<uint64_t>& record_ids) {
    // TODO need to speed up
    for (uint64_t rid : record_ids) {
        DeleteRecord(rid);
    }
}

void DataChunkDeleteBitmap::AppendChunk(uint64_t record_count) {
    AppendChunk();
}

void DataChunkDeleteBitmap::AppendChunk() {
    uint64_t expand_size = (RECORD_COUNT_PER_CHUNK+63)/64;
    uint64_t mask = 0;
    for (int i = 0; i < expand_size; i++) {
        db_io_.write(reinterpret_cast<char *>(&mask), sizeof(mask));
    }
    db_io_.flush();
}

}